package edu.friday.service.impl;

import edu.friday.common.constant.UserConstants;
import edu.friday.common.result.TreeSelect;
import edu.friday.model.SysMenu;
import edu.friday.model.vo.MetaVo;
import edu.friday.model.vo.RouterVo;
import edu.friday.model.vo.SysMenuVO;
import edu.friday.model.vo.SysUserVO;

import edu.friday.repository.SysMenuRepository;
import edu.friday.service.SysMenuService;
import edu.friday.utils.BeanUtils;
import edu.friday.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl implements SysMenuService {
    @Autowired
    SysMenuRepository sysMenuRepository;

    @Override
    public Set<String> selectMenuPermsByUserId(Long userId){
        List<String> perms = sysMenuRepository.selectMenuPermsByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for(String perm: perms){
            if(StringUtils.isNotEmpty(perm)){
                permsSet.addAll(Arrays.asList( perm.trim().split(",")));
            }
        }

        return permsSet;
    }

    @Override
    public List<SysMenu> selectMenuList(SysMenuVO menu, Long userId) {
        List<SysMenu> menuList= null;
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyPropertiesIgnoreEmpty(menu,sysMenu);
        Sort sort = Sort.by("parentId","orderNum");
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("menuName",ExampleMatcher.GenericPropertyMatchers.contains());
        Example example = Example.of(sysMenu,exampleMatcher);
        if(SysUserVO.isAdmin(userId)){
            menuList = sysMenuRepository.findAll(example,sort);
        }else {
            menuList = sysMenuRepository.selectMenuListByUserId(sysMenu,userId);
        }
        return menuList;
    }

    @Override
    public String checkMenuNameUnique(SysMenu menu) {
        Long menuId  =StringUtils.isNull(menu.getMenuId()) ?-1L:menu.getMenuId();
        SysMenu sysMenu = new SysMenu();
        sysMenu.setParentId(menu.getParentId());
        sysMenu.setMenuName(menu.getMenuName());

        Page<SysMenu>list = sysMenuRepository.findAll(Example.of(sysMenu), PageRequest.of(0,1));
        SysMenu info = null;
        if(list.getTotalElements()>0){
            info =list.toList().get(0);
        }
        if(StringUtils.isNotNull(info) && info.getMenuId().longValue()!=menuId.longValue()){
            return UserConstants.NOT_UNIQUE;
        }
        return  UserConstants.UNIQUE;
    }

    @Override
    public int insertMenu(SysMenu menu) {
        sysMenuRepository.save(menu);
        return (menu!=null && null!=menu.getMenuId())?1:0;
    }

    @Override
    public int updateMenu(SysMenu menu) {
        SysMenu sysMenu = new SysMenu();
        Optional<SysMenu> op = sysMenuRepository.findById(menu.getMenuId());
        if (!op.isPresent()) {
            return 0;
        }
        sysMenu = op.get();
        BeanUtils.copyPropertiesIgnoreNull(menu,sysMenu);
        sysMenuRepository.save(sysMenu);
        return 1;
    }

    @Override
    public SysMenu selectMenuById(Long menuId) {
        Optional<SysMenu> op =  sysMenuRepository.findById(menuId);
        return op.isPresent() ? op.get() : null;
    }

    @Override
    public boolean hasChildByMenuId(Long menuId) {
        SysMenu sysMenu = new SysMenu();
        sysMenu.setParentId(menuId);
        long result = sysMenuRepository.count(Example.of(sysMenu));
        return  result>0;
    }

    @Override
    public boolean checkMenuExistRole(Long menuId) {
        long result = sysMenuRepository.checkMenuExistRole(menuId);
        return  result>0;
    }

    @Override
    public int deleteMenuById(Long menuId) {
        sysMenuRepository.deleteById(menuId);
        return 1;
    }

    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenuVO> menus) {
        List<SysMenuVO> menuTrees = buildMenuTree(menus);
        List<TreeSelect> rs = menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
        return rs;
    }

    private List<SysMenuVO> buildMenuTree(List<SysMenuVO> menus) {
        List<SysMenuVO> returnList = new ArrayList<>();
        for (Iterator<SysMenuVO> iterator = menus.iterator();iterator.hasNext();){
            SysMenuVO t = iterator.next();
            if(t.getParentId()==0){
                recursionFn(menus,t);
                returnList.add(t);
            }
        }
        if(returnList.isEmpty()){
            returnList=menus;
        }
        return returnList;
    }

    @Override
    public List<Long> selectMenuListByRoled(Long roleId) {
        List<SysMenu> menuList =sysMenuRepository.selectMenuListByRoleId(roleId);
        List<Long> idList = new ArrayList<>();
        for (SysMenu menu: menuList){
            idList.add(menu.getMenuId());
        }
        return idList;
    }


    @Override
    public List<SysMenu> selectMenuList(Long userId) {
        SysMenuVO sysMenuVO  =new SysMenuVO();
        return  selectMenuList(sysMenuVO,userId);
    }

    @Override
    public List<SysMenuVO> selectMenuTreeByUserId(Long userId) {
        List<SysMenu> menus =null;
        if(SysUserVO.isAdmin(userId)){
            menus = sysMenuRepository.selectMenuTreeAll();
        }else{
            menus=sysMenuRepository.selectMenuTreeByUserId(userId);
        }
        List<SysMenuVO> menuVOS = BeanUtils.copyProperties(menus,SysMenuVO.class);

        return getChildPerms(menuVOS,0);
    }

    private List<SysMenuVO> getChildPerms(List<SysMenuVO> list, int parentId) {
        List<SysMenuVO> returnList = new ArrayList<>();
        for (Iterator<SysMenuVO> iterator = list.iterator();iterator.hasNext();){
            SysMenuVO t = iterator.next();
            if(t.getParentId()==parentId){
                recursionFn(list,t);
                returnList.add(t);
            }
        }
        return returnList;
    }



    public List<RouterVo> buildMenus(List<SysMenuVO> menus){
        List<RouterVo> routers = new LinkedList<>();
        for(SysMenuVO menu :menus){
            RouterVo router = new RouterVo();
            router.setName(StringUtils.capitalize(menu.getPath()));
            router.setPath(getRouterPath(menu));
            router.setComponent(StringUtils.isEmpty(menu.getComponent())?"Layout":menu.getComponent());
            router.setMeta(new MetaVo(menu.getMenuName(),menu.getIcon()));
            List<SysMenuVO> cMenus = menu.getChildren();
            if(!cMenus.isEmpty() && cMenus.size()>0 && "M".equals(menu.getMenuType())){
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    private String getRouterPath(SysMenuVO menu) {
        String routerPath = menu.getPath();
        if(0== menu.getParentId() && "1".equals(menu.getIsFrame())){
            routerPath="/"+menu.getPath();
        }
        return routerPath;
    }

    private void recursionFn(List<SysMenuVO> list,SysMenuVO t){
        List<SysMenuVO> childList = getChildList(list,t);
        t.setChildren(childList);

        for (SysMenuVO tChild:childList){
            if (hasChild(list,tChild)){
                Iterator<SysMenuVO> it = childList.iterator();
                while(it.hasNext()){
                    SysMenuVO n  = it.next();
                    recursionFn(list,n);
                }
            }
        }
    }

    private List<SysMenuVO> getChildList(List<SysMenuVO> list,SysMenuVO t) {
        List<SysMenuVO> tList = new ArrayList<>();
        Iterator<SysMenuVO> it = list.iterator();
        while (it.hasNext()) {
            SysMenuVO n = it.next();
            if (n.getParentId().longValue()==t.getMenuId().longValue()) {
                tList.add(n);
            }
        }
           return  tList;
    }

    private  boolean hasChild(List<SysMenuVO>list ,SysMenuVO t){
        return  getChildList(list,t).size()>0;
    }
}
